/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package classloader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Oksana_Moroz
 */

public class DynamicClassLoader extends ClassLoader {
    
    private String folder;
    
    public DynamicClassLoader() {
        folder = "";
    }

    public DynamicClassLoader(String folder) {
        this.folder = folder;
    }
    
    public void setFolder(String folder) {
        this.folder = folder;
    }
    
    private boolean compile(String javaFile) throws IOException {
        System.out.println("Compiling " + javaFile);
        
        Process p = Runtime.getRuntime().exec("javac " + javaFile);
        try {
            p.waitFor();
        } catch (InterruptedException ex) {
            Logger.getLogger(DynamicClassLoader.class.getName()).log(Level.SEVERE, null, ex);
        }
        int code = p.exitValue();
        return (code == 0);
    }
    
    private byte[] getBytes(String classPath) throws IOException {
        File file = new File(classPath);
        long len = file.length();
        byte[] bytes = new byte[(int) len];
        FileInputStream fis = new FileInputStream(file);
        int r = fis.read(bytes);
        if (r != len) {
            throw new IOException("Can`t read all bytes!");
        }
        fis.close();
        return bytes;
    }
    
    @Override
    protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
        // See, if we have already loaded this class
        Class clazz = findLoadedClass(name);
                
        // Create a path to file from file name
        String filePath = name.replace('.', '/');
        
        String javaPath = folder + "/" + filePath + ".java";
        String classPath = folder + "/" + filePath + ".class";
        
        File javaFile = new File(javaPath);
        File classFile = new File(classPath);
        
        // See, if we need recompiling
        if (javaFile.exists() &&
                (!classFile.exists() 
                || (javaFile.lastModified() > classFile.lastModified()))) {
            try {
                if (!compile(javaPath) || !classFile.exists()) {
                    throw new ClassNotFoundException("Compiling failed: " + javaPath);
                }
            } catch (IOException ex) {
                throw new ClassNotFoundException(ex.toString());
            }
        }
        
        // Try to load class bytes
        try {            
            byte[] bytes = getBytes(classPath);
            clazz = defineClass(name, bytes, 0, bytes.length);
        } catch (IOException ex) {            
            // If we reach here, it might mean that we are dealing 
            // with a class in a library, such as java.lang.Object
        }
        
        // It may be a system class, try to load in default way
        if (clazz == null) {
            clazz = findSystemClass(name);
        }
        
        // Resolve the class, it it is not null
        if (resolve && (clazz != null)) {
            resolveClass(clazz);
        }
        
        if (clazz == null) {
            throw new ClassNotFoundException(name);
        }
        
        return clazz;
    }
}
